//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Implementacao de classe para biblioteca de minimizacao da gsl.
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_deriv.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_multimin.h>

class GSL_Multimin_fdf {
  const gsl_multimin_fdfminimizer_type *_gslType_;
  gsl_multimin_fdfminimizer *_gslMin_;
  gsl_vector *_x_;
  gsl_multimin_function_fdf *_minFunc_;
  int _itr_;
  int _size_;//numero de parametros de entrada...
  double _stsize_;//tamanho do passo inicial...
  double _tol_;
  public:
    GSL_Multimin_fdf(const int sz, gsl_multimin_function_fdf &my_func,const gsl_vector * x,
		     double step_size, double tol)
    {
      size(sz);
      _gslType_ = gsl_multimin_fdfminimizer_conjugate_fr;
      _gslMin_ = gsl_multimin_fdfminimizer_alloc (_gslType_, sz);
      _minFunc_=&my_func;
      _x_ = gsl_vector_alloc (sz);
      _stsize_ = step_size;
      _tol_=tol;
      _itr_=0;
      //copiando vetor inicial para memoria
      for(int i = 0; i < sz; i++)
	gsl_vector_set(_x_,i,gsl_vector_get(x,i));
      gsl_multimin_fdfminimizer_set(_gslMin_,_minFunc_,_x_,_stsize_,_tol_);
    };
    ~GSL_Multimin_fdf(){
      gsl_vector_free(_x_);
      gsl_multimin_fdfminimizer_free(_gslMin_);
    };
    void inline size(const int sz){_size_=sz;};
    int inline size(void){return _size_;};
    
    int iterate(void){_itr_++;return gsl_multimin_fdfminimizer_iterate(_gslMin_);};
    double test_Grad(double epsabs){return gsl_multimin_test_gradient(_x_,epsabs);};
    
    int iteration(void){return _itr_;};
    double score(void){return _gslMin_->f;};
    gsl_vector* BestEstimate(void)
    {
      return gsl_multimin_fdfminimizer_x (_gslMin_);
    };
    void restart(void)
    {
      gsl_multimin_fdfminimizer_set(_gslMin_,_minFunc_,BestEstimate(),_stsize_,_tol_);
	  //gsl_multimin_fdfminimizer_restart(_gslMin_);
    }
};

class GSL_Multimin_f {
  const gsl_multimin_fminimizer_type *_gslType_;
  gsl_multimin_fminimizer *_gslMin_;
  gsl_vector *_x_;
  gsl_vector *_xsize_;
  gsl_multimin_function *_minFunc_;
  int _itr_;
  int _size_;//numero de parametros de entrada...
  double _stsize_;//tamanho do passo inicial...
  double _tol_;
  public:
    GSL_Multimin_f(const int sz, gsl_multimin_function &my_func,const gsl_vector * x,
		   const gsl_vector * xsize,double tol)
    {
      size(sz);
      _gslType_ = gsl_multimin_fminimizer_nmsimplex;
      _gslMin_ = gsl_multimin_fminimizer_alloc (_gslType_, sz);
      _minFunc_=&my_func;
      _x_ = gsl_vector_alloc (sz);
      _xsize_ = gsl_vector_alloc (sz);
      //_stsize_ = step_size;
      _tol_=tol;
      _itr_=0;
      //copiando vetor inicial para memoria
      for(int i = 0; i < sz; i++){
	gsl_vector_set(_x_,i,gsl_vector_get(x,i));
	gsl_vector_set(_xsize_,i,gsl_vector_get(xsize,i));
      }
      gsl_multimin_fminimizer_set(_gslMin_,_minFunc_,_x_,_xsize_);
    };
/*    ~GSL_Multimin_fdf(){
    gsl_vector_free(_x_);
    gsl_multimin_fdfminimizer_free(_gslMin_);
};*/
    void inline size(const int sz){_size_=sz;};
    int inline size(void){return _size_;};
    
    int iterate(void){_itr_++;return gsl_multimin_fminimizer_iterate(_gslMin_);};
    //double test_Grad(double epsabs){return gsl_multimin_test_gradient(_x_,epsabs);};
    
    int test_size(double size)
    {
      return gsl_multimin_test_size(gsl_multimin_fminimizer_size(_gslMin_), size);
    };
    double inline simplex_size(void){return gsl_multimin_fminimizer_size(_gslMin_);};
    int test_size(void)
    {
      return gsl_multimin_test_size(gsl_multimin_fminimizer_size(_gslMin_), _tol_);
    };
    
    int iteration(void){return _itr_;};
    double score(void){return _gslMin_->fval;};
    gsl_vector* BestEstimate(void)
    {
      return gsl_multimin_fminimizer_x (_gslMin_);
    };
    void restart(void)
    {
      gsl_multimin_fminimizer_set(_gslMin_,_minFunc_,BestEstimate(),_xsize_);
    }
};
